一般我們執行程式碼都是直接回傳值,這稱為同步;異步跟這行為相反,我們執行程式碼時,也許因為該段程式碼需要花費時間去執行、也或許需要等待資料,這個時候,我們真實需要的資料、結果沒有辦法在執行程式碼之後直接取得,此時,我們就必須要使用異步的方式來執行程式。
在 Dart 中,異步工作分為兩種:Future
、 Stream
。
Future 是用在結果會在未來完成的情況,而 Stream 是用在資料流的情況。
針對異步的工作 Dart 提供了關鍵字 async
以及 await
來處理它。
在 Dart/Flutter 中,有許多 API 都是以 Future 來處理資料,例如 Http 請求 (Http request)、SharedPreference ...
在 Future
類別中,包含了幾個常用的靜態函數,方便我們直接建立一個 Future
。
Future<int> futureWait(){
return Future.value(10);
}
void main(){
futureWait().then((value)=>print(value));
}
//10
Future
有什麼好處呢?Future 類別包含了幾個函數,我們可以直接串接在 Future 之後。
如上方範例的 then
:
then(value)
:在 Future 的數值回傳之後,就可以在 then
裡面使用這個數值,如 print(value)
。whenComplete()
:當 Future 完成之後,最後就會呼叫到 whenComplete
。void main(){
futureWait().then((value) => print(value))
.whenComplete(()=> print('done'));
}
//10
//done
在測試 Future 時, Future.delayed
是最方便的一個函數。
在 Future.delayed 中帶入一個 Duration
,時間到了之後就會執行 Future 內的函數。
Future<String> futureDelayed(){
return Future.delayed(Duration(seconds: 1),
() => 'Delay 1 second');
}
void main(){
futureDelayed().then((value) => print(value));
}
//Delay 1 second
then
將數值列印出來。除了正確的資料外,當錯誤發生時,我們也可以用 Future 將錯誤捕捉起來。 Future.error
可以發出一個 Future 的 錯誤。
Future<String> futureError(){
return Future.error('error message');
}
void main(){
futureError().catchError((error) => print(error));
}
//error message
catchError
函數來捕捉。前面提到,Dart 是用 async
以及 await
關鍵字來處理異步。
那麼要如何使用呢?
呼叫異步函數的時候,每一個異步函數回傳的時間都不一樣,如果我們需要等待異步函數的回傳值才繼續,我們就可以使用 async
以及 await
關鍵字。
例如:
假設有兩個 Future 函數,一個需要花費一秒回傳10,另一個直接回傳 true。
void testFutureMethod(){
futureMethod1().then((value)=> print(value));
futureMethod2().then((value) => print(value));
}
Future<int> futureMethod1(){
return Future.delayed(Duration(seconds: 1), ()=>10);
}
Future<bool> futureMethod2(){
return Future.value(true);
}
void main(){
testFutureMethod();
}
//true
...1 second...
//10
結果會先傳出方法2的回傳值 true,接者才是方法1 的 10。
因為異步沒有順序,會根據完成的順序來回傳。
async
以及 await
將 testFutureMethod 函數加上 async
以及 await
關鍵字。
async
:用來表示該函數是異步函數。
await
:用來表示要等待異步函數完成。
void testFutureMethod() async{
await futureMethod1().then((value)=> print(value));
await futureMethod2().then((value) => print(value));
}
void main(){
testFutureMethod();
}
...1 second...
//10
//true
async
以及 await
關鍵字變得有順序了。Future
表示會回傳是的值可能會經過一些運算時間,可能會需要多一些時間等待。有時候不見得是本機端很忙需要等待,網路的請求常常也會需要一些時間,所以在網路的應用上很常見到 Future 。
Future 的結果會有兩種,一種是正常的結果,另一種是錯誤的結果。我們可以用 then
來處理 Future 函數的正常結果,用 catchError
處理異常的結果。
異步,表示完成的時間不一樣,如果需要在同一個函數中進行有順序的異步函數呼叫。可以使用async
以及 await
關鍵字。
利用 async
將函數宣告成異步函數。用 await
決定要等待哪一個函數。
在 async 函數中,可以使用多個 await。使用 await 一定要在 async 函數中。